
package com.zjh.common.annotation;


import com.zjh.common.exception.ServiceException;
import com.zjh.common.utils.RequestContext;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 初次访问通过传统方式获取数据，并将数据放到Redis中
 */
@Aspect
@Component
public class RedisCacheableAspect {

    private final AtomicBoolean isRefreshing = new AtomicBoolean(false);
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Around("@annotation(redisCacheable)")
    public Object controllerCache(ProceedingJoinPoint joinPoint, RedisCacheable redisCacheable) throws Throwable {
        String loginDept = RequestContext.getLoginUser().getUsername();
        long intervalInMinutes = Long.parseLong(redisCacheable.refreshInterval());

        String cacheKey = redisCacheable.cacheKey();
        String finalKey = cacheKey + ":" + loginDept;
        Object cacheResult = redisTemplate.opsForValue().get(finalKey);
        if (cacheResult != null) {
            if (isRefreshing.compareAndSet(false, true)) {
                new Thread(() -> {
                    try {
                        Object result = joinPoint.proceed();
                        redisTemplate.opsForValue().set(finalKey, result, intervalInMinutes, TimeUnit.MINUTES);
                    } catch (Throwable e) {
                        throw new ServiceException(e);
                    } finally {
                        isRefreshing.set(false);
                    }
                }).start();
            }
            return cacheResult;
        }

        Object result = joinPoint.proceed();
        redisTemplate.opsForValue().set(finalKey, result, intervalInMinutes, TimeUnit.MINUTES);

        return result;
    }

}
